R cuenta con varios paquetes de funciones que permiten trabajar con bases SQL con facilidad. A continuación vamos a ver algunas herramientas y ejemplos de como trabajar las bases de datos de la BdeC con R.
Paquetes
Hay dos paquetes útiles para trabajar bases SQL DBI y RODBC. Asimismo, dplyr cuenta con funciones que permiten exportar las consultas a formato SQL.
library(RODBC)
library(tidyverse)
library(dbplyr)
Conexión a la base y consultas
Me conecto a la base con la funcion odbcDriverConnect.
ch <- odbcDriverConnect(
connection = "Driver=SQL Server; Server=BC-RETA;
Database=Estimaciones_copia;
UID=estimaciones_consulta;
Pwd=Esti.bc.201923"
)
Consulta SQL
sqlQuery permite utilizar el codigo de sql en R. La consulta se inserta como string.
En esta consulta seleccionamos se combinan 5 tablas y se selecciona para el cultivo trigo, en la campaña 18/19, en el nivel tecnologico alto, en la zona Retaa 5 las dosis de fertilizacion promedio.
consulta_Ruben <- sqlQuery(channel = ch, query = "--/////////////////////////////////////////////
--@id_consulta
--6 Fertilización
--7 Herbicidas
--8 Insecticidas
--3 Siembra
--10 Tratamiento de semilla
--9 Fungicidas
--/////////////////////////////////////////////
--@id_grano
--1 Trigo
--2 Cebada
--3 Girasol
--4 Sorgo
--5 Soja 1°
--6 Soja 2°
--7 Maíz 1° Temprano
--8 Maíz 1° Tardio y 2°
--/////////////////////////////////////////////
--@id_nivel
--1 Alto
--2 Medio
--3 Bajo
--/////////////////////////////////////////////
--@id_zona
--1 I NOA
--2 IIe NEA Este (Chaco y Formosa)
--3 III Ctro N Cba
--4 IV S Cba
--5 Vc Ctro N SFe
--6 VI Núcleo Norte
--7 VII Núcleo Sur
--8 VIII Ctro E ER
--9 IX N LP-OBA
--10 X Ctro BA
--11 XI SO BA-S LP
--12 XII SE BA
--13 XIII San Luis
--14 XIV Cuenca Sal
--15 XV Corrientes-Misiones
--16 IIo NEA Oeste (este de Sgo. del Estero)
--17 Vn Norte SFe
--/////////////////////////////////////////////
--@id_campaña
--1 2010/2011
--2 2011/2012
--3 2012/2013
--4 2013/2014
--5 2014/2015
--6 2015/2016
--7 2016/2017
--8 2017/2018
--9 2018/2019
--10 2019/2020
declare @id_campaña int
declare @id_consulta int
declare @id_grano int
declare @id_nivel int
declare @id_zona int
set @id_campaña= 9 -- 2018/2019
set @id_consulta= 6--Fertilización
set @id_grano = 1 --Trigo
set @id_nivel= 1 -- nivel 1
set @id_zona = 5 -- Vc Ctro N SFe
SELECT (SELECT descripcion
FROM Tipo_promedios
WHERE (id = 1)) AS des_prom, 1 AS tipo_promedio, xx.id, xx.id_grano,
gg.descripcion AS des_grano, cc.id_tipo_pregunta, cc.id_caract,
cc.descripcion AS des_caract, nn.descripcion AS des_nivel, xx.id_nivel,
xx.id_zona, zz.descripcion AS Expr1, zz.descripcion2,
CAST(ISNULL((SELECT SUM(max) / COUNT(1) AS Expr1
FROM(SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.max IS NOT NULL) AND (t.id_grano = xx.id_grano) AND
(t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta FROM tipo_pregunta_retaa AS
p LEFT OUTER JOIN Tipo_caracteristicas_retaa AS
c ON p.id = c.id_tipo_pregunta WHERE (p.id_filtro IN
(cc.id_tipo_pregunta)) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_max, 'http://bc-sellos/PruebaRetaa/pop_up_X_rubros.aspx?par=' + CAST(@id_campaña AS nvarchar(1))
+ ';' + CAST(xx.id_grano AS nvarchar(2)) + ';' + CAST(xx.id_zona AS nvarchar(2)) + ';' + CAST(cc.id_tipo_pregunta AS nvarchar(2)) + ';' + CAST(cc.id_caract_2 AS nvarchar(3)) + ';' + CAST(xx.id_nivel AS nvarchar(3)) + ';' + '0' AS URL,
CAST(ISNULL
((SELECT SUM(min) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.min, 0) AS min
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.min IS NOT NULL) AND (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_7
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_min, ISNULL
((SELECT SUM(max_null) / COUNT(1) AS Expr1
FROM (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .max, 0) ELSE ISNULL(t .max, 0) * porc_aplic / 100 END) AS max_null
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_6
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1), 0) AS Alto_Promedio_max_null, ISNULL
((SELECT SUM(max_null) / COUNT(1) AS Expr1
FROM (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .min, 0) ELSE ISNULL(t .min, 0) * porc_aplic / 100 END) AS max_null
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_5
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1_1), 0) AS Alto_Promedio_min_null, cc.id_indice,
(SELECT descripcion
FROM tipo_pregunta_retaa
WHERE (id =
(SELECT id_filtro
FROM tipo_pregunta_retaa AS tipo_pregunta_retaa_3
WHERE (id IN (cc.id_tipo_pregunta))))) AS des_consulta, CAST
(((SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_2
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2) +
(SELECT SUM(min) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.min, 0) AS min
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_1
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.min_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_1
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1_1)) / 2 / 100 *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie_2, CAST
((SELECT superficie
FROM Superficie_retaa_x_campaña_grano
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie, zz.indice,
(SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta = 2) AND (t.nivel = xx.id_nivel) AND (t.id_caract = 4) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_4
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1) AS Alto_Promedio_max_distribucion,
(SELECT SUM(max) / COUNT(1) AS Expr1
FROM (SELECT ISNULL(t.max, 0) AS max
FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
WHERE (t.id_grano IN
(SELECT ID_MAPA
FROM Tipo_grano_reportes
WHERE (id = gg.id_grano_report))) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
(SELECT TOP (1) id_tipo_pregunta
FROM caract_id_grano AS caract_id_grano_2
WHERE (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
((SELECT COUNT(1) AS Expr1
FROM cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
WHERE (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2_1) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS superficie_3,
(SELECT primera
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_2
WHERE (id_grano =
(SELECT id_grano_report
FROM Tipo_grano AS Tipo_grano_2
WHERE (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_3
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS Pas_primera_superficie,
(SELECT segunda
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
WHERE (id_grano =
(SELECT id_grano_report
FROM Tipo_grano AS Tipo_grano_1
WHERE (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
(SELECT superficie
FROM Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_4
WHERE (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS pas_segunda_superficie, cc.tipo_unidad, CASE WHEN cc.id_tipo_pregunta = 7 OR
cc.id_tipo_pregunta = 6 THEN
(SELECT TOP (1) Coeficiente
FROM Tipo_caracteristicas_retaa
WHERE id_caract = cc.id_caract) ELSE '-1' END AS coeficiente, l.descripcion AS campaña
FROM Granos_zonas_retaa AS xx LEFT OUTER JOIN
Tipo_zona_retaa AS zz ON xx.id_zona = zz.id_zona LEFT OUTER JOIN
Tipo_nivel AS nn ON xx.id_nivel = nn.id_nivel LEFT OUTER JOIN
Tipo_grano AS gg ON xx.id_grano = gg.id LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS cc ON xx.id_grano = cc.id_grano AND cc.id_tipo_pregunta IN
(SELECT c.id_tipo_pregunta
FROM tipo_pregunta_retaa AS p LEFT OUTER JOIN
Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
WHERE (p.id_filtro IN (@id_consulta)) AND (c.id_grano = xx.id_grano)
GROUP BY c.id_tipo_pregunta) LEFT OUTER JOIN
Año_campañas AS l ON cc.id_campaña = l.id
WHERE (xx.id_grano IN (@id_grano)) AND (xx.id_zona IN (@id_zona)) AND (xx.id_nivel IN (@id_nivel)) AND (cc.id_caract_2 <> 104) AND (cc.id_caract_2 <> 105) AND (cc.id_caract_2 <> 106) AND (cc.id_caract_2 <> 107) AND (cc.id_caract_2 <> 108) AND
(cc.id_caract_2 <> 65) AND (cc.id_campaña = @id_campaña);")
consulta_Ruben
Paquete DBI
DBI permite conectarno a la base de datos de SQL. Para hacerlo debemos configurar los campos. La conexión se puede verificar en el panel superior derecho.
La base datos del ReTAA esta compuesta por 6 tablas principales “Año Campañas”, “cabecera_trnsacciones_retaa”, “caract_id_grano”, “caract_id_grano_campaña_vista”, “Colaboradores” y “Granos_zonas_retaa”.
#Me conecto a la base
con <- DBI::dbConnect(odbc::odbc(),
Driver = "SQL Server",
Server = "BC-RETA",
Database = "Estimaciones_copia",
UID = "estimaciones_consulta",
PWD = "Esti.bc.201923",
Port = 1433,
dbname = "Estimaciones_Copia",
encoding = "latin1")
DBI::dbListTables(con)[1:6]#lista de las tablas de la base
[1] "Año_campañas" "cabecera_transacciones_retaa" "caract_id_grano"
[4] "caract_id_grano_campaña_vista" "Colaboradores" "Granos_zonas_retaa"
la función tbl de dplyr trae las tablas de la base de datos. Tambien podemos aplicar a esta tabla todas las funciones que vimos en las clases previas.
Veamos algunas de las tablas que conforman la base del ReTAA.
Tabla Tipo_grano
#Tabla id grano
Tipo_grano <- tbl(con, c("Tipo_grano")) %>%
select(id,descripcion) %>% rename(id_grano = id, descripcion_grano = descripcion) %>% filter(id_grano>0)
Tipo_grano
Tabla cabecera_transacciones_retaa
Tabla Tipo_caracteristicas_retaa
#Tabla caracteristicas retaa (Principal)
Tipo_caracteristicas_retaa <- tbl(con, c("Tipo_caracteristicas_retaa_trans"))
Tipo_caracteristicas_retaa %>% head(10)
Tabla Colaboradores
Colaboradores %>% variable.names()
[1] "id_colaborador" "id_Zona" "id_semana" "fec_alta"
[5] "Empresa" "Nombre" "Apellido" "Localidad"
[9] "Provincia" "Telefono" "Celular" "e_mail"
[13] "obs" "poligono" "id_usuario" "fec_ultimaMod"
[17] "id_usuarioMod" "Emp_vinculada" "estado" "direccion"
[21] "cp" "dto" "localidad1" "tipo_nivel"
[25] "id_zona_retaa" "id_estado_retaa" "obs_retaa" "latitud"
[29] "logitud"
Tambien podemos visualizar las conexxiones entre las tablas con el paquete datamodelr que nos permite construir diagramas entidad-realación
library(datamodelr) #paquete para armar diagrama de entidad relacion
coneccion <- odbcDriverConnect(
connection = "Driver=SQL Server; Server=BC-RETA; Database=Estimaciones_copia; UID=estimaciones_consulta; Pwd=Esti.bc.201923"
)
sQuery <- dm_re_query("sqlserver")
dm_retaa <- sqlQuery(channel = coneccion, sQuery, stringsAsFactors = FALSE, errors=TRUE)
dm_retaa <- as.data_model(dm_retaa) #paso a formato modelo
focus <-list(tables = c("Año_campañas","cabecera_transacciones_retaa","caract_id_grano",
"caract_id_grano_campaña_vista","Colaboradores","Granos_zonas_retaa"))
graph <- dm_create_graph(dm_retaa , rankdir = "BT", focus = focus, col_attr = c("column", "type"))
dm_render_graph(graph) #grafico
Query SQL vs dplyr
En esta seccion vamos a replicar la consulta SQL que vimos arriba pero en fomrato dplyr. Vamos a ver que una consulta muy extensa se puede realizar en una fomra más prolija y breve.
El comandoshow_query permite extraer la consulta en formato SQL.
tabla_consulta_sql <- Tipo_caracteristicas_retaa %>%
left_join(cabecera_transacciones_retaa,by = c("id_trans","id_colaborador")) %>% #join con tabla cabecera
left_join(Tipo_grano ,by = "id_grano") %>%
left_join(Anio_campanias ,by = c("id_campaña"="id_campania") ) %>%
left_join(Tipo_zona_retaa, by = c("id_zona") ) %>%
filter(id_campaña == 9,id_zona==5,nivel==1,id_grano==1,id_tipo_pregunta==6, max_estado == 1, estado==1) %>%
group_by(descripcion_grano, id_grano, descripcion_campania, id_campaña, descripcion_zona_retaa, id_zona,
nivel, id_tipo_pregunta, id_caract,descripcion) %>%
summarise(promedio_max = round(mean(max, na.rm = T),2),
promedio_min = round(mean(min, na.rm = T),2))
tabla_consulta_sql %>% dplyr::show_query() #ver query SQL
<SQL>
SELECT "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion", ROUND(AVG("max"), 2) AS "promedio_max", ROUND(AVG("min"), 2) AS "promedio_min"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "LHS"."descripcion_campania" AS "descripcion_campania", "RHS"."descripcion_zona_retaa" AS "descripcion_zona_retaa", "RHS"."descripcion_zona_retaa2" AS "descripcion_zona_retaa2"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "RHS"."descripcion_campania" AS "descripcion_campania"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "RHS"."descripcion_grano" AS "descripcion_grano"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "RHS"."estado" AS "estado"
FROM "Tipo_caracteristicas_retaa_trans" AS "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_trans", "id_colaborador", "estado"
FROM "cabecera_transacciones_retaa") "RHS"
ON ("LHS"."id_trans" = "RHS"."id_trans" AND "LHS"."id_colaborador" = "RHS"."id_colaborador")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_grano", "descripcion" AS "descripcion_grano"
FROM "Tipo_grano") "dbplyr_145"
WHERE ("id_grano" > 0.0)) "RHS"
ON ("LHS"."id_grano" = "RHS"."id_grano")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_campania", "descripcion" AS "descripcion_campania"
FROM "Año_campañas") "dbplyr_146"
WHERE ("id_campania" > 0.0)) "RHS"
ON ("LHS"."id_campaña" = "RHS"."id_campania")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_zona", "descripcion" AS "descripcion_zona_retaa", "descripcion2" AS "descripcion_zona_retaa2"
FROM "Tipo_zona_retaa") "RHS"
ON ("LHS"."id_zona" = "RHS"."id_zona")
) "dbplyr_147"
WHERE (("id_campaña" = 9.0) AND ("id_zona" = 5.0) AND ("nivel" = 1.0) AND ("id_grano" = 1.0) AND ("id_tipo_pregunta" = 6.0) AND ("max_estado" = 1.0) AND ("estado" = 1.0))
GROUP BY "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion"
tabla_consulta_sql #salida
Planteos Tecnologicos
Construir los planteos tecnológicos suele ser un trabajo que tedioso que no esta automatizado y suele tomar bastante tiempo. En esta sección buscamos automatizar la construcción de los planteos.
planteos_long <- planteos %>% pivot_longer(cols = -c(1:8,Adopcion_NT), names_to = "variables", values_to = "valores") %>% mutate(valores = ifelse(is.na(valores),0,valores)) %>% group_by(id_campaña,descripcion_campania,id_zona,
descripcion_zona_retaa, id_grano,descripcion_grano, variables) %>% summarise(valores = weighted.mean(valores ,w = Adopcion_NT/100))
planteos_long %>% head()
variables_planteo_soja <-c("Semilla", "SPS","Glifosato concentrado - Barbecho",
"Glifosato concentrado - cultivo", "2-4D","Clorimurón",
"Metsulfurón","Diclosulam","Diamidas","Estrobirulina + Triazol",
"Inoculante 1 (full)","Inoc. + Fungic.") #Lambdacialotrina no lo encontré
planteos_long %>%
filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>%
ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(id_zona)))+
geom_point() + facet_wrap(~variables, scales = "free_y")+
labs(title = "Dosis aplicadas - Soja 1º")+
labs(x="Campaña", fill="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "none"
)

Análisis exploratorio de datos
Evolución del nivel tecnológico
planteos %>% filter(descripcion_grano=="Maíz 1° Temprano") %>%
ggplot(.,mapping = aes(x = descripcion_campania, y = Adopcion_NT, group=nivel,fill = as.factor(descripcion_nivel))) +
geom_col() +
facet_wrap(~descripcion_zona_retaa)+ theme_bw()+
labs(title = "Nivel tecnológico por zona - Maíz temprano")+
labs(x="Campaña", fill="Nivel tecnológico")+
theme(axis.text.x = element_text(angle = 90),
legend.position = "bottom"
)

Dosis de fertilización Urea

LS0tDQp0aXRsZTogQmFzZXMgU1FMIGVuIFINCnN1YnRpdGxlOiBJbnRyb2R1Y2Npw7NuDQpkYXRlOiAiIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNClIgY3VlbnRhIGNvbiB2YXJpb3MgcGFxdWV0ZXMgZGUgZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiB0cmFiYWphciBjb24gYmFzZXMgU1FMIGNvbiBmYWNpbGlkYWQuIEEgY29udGludWFjacOzbiB2YW1vcyBhIHZlciBhbGd1bmFzIGhlcnJhbWllbnRhcyB5IGVqZW1wbG9zIGRlIGNvbW8gdHJhYmFqYXIgbGFzIGJhc2VzIGRlIGRhdG9zIGRlIGxhIEJkZUMgY29uIFIuDQoNCg0KIyMjIFBhcXVldGVzDQoNCkhheSBkb3MgcGFxdWV0ZXMgw7p0aWxlcyBwYXJhIHRyYWJhamFyIGJhc2VzIFNRTCBgREJJYCB5IGBST0RCQ2AuIEFzaW1pc21vLCBgZHBseXJgIGN1ZW50YSBjb24gZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiBleHBvcnRhciBsYXMgY29uc3VsdGFzIGEgZm9ybWF0byBTUUwuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KFJPREJDKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRicGx5cikNCmBgYA0KDQojIyMgQ29uZXhpw7NuIGEgbGEgYmFzZSB5IGNvbnN1bHRhcw0KDQpNZSBjb25lY3RvIGEgbGEgYmFzZSBjb24gbGEgZnVuY2lvbiBvZGJjRHJpdmVyQ29ubmVjdC4NCg0KYGBge3J9DQpjaCA8LSBvZGJjRHJpdmVyQ29ubmVjdCgNCiAgY29ubmVjdGlvbiA9ICJEcml2ZXI9U1FMIFNlcnZlcjsgU2VydmVyPUJDLVJFVEE7DQogICAgICAgICAgICAgICAgRGF0YWJhc2U9RXN0aW1hY2lvbmVzX2NvcGlhOw0KICAgICAgICAgICAgICAgIFVJRD1lc3RpbWFjaW9uZXNfY29uc3VsdGE7DQogICAgICAgICAgICAgICAgUHdkPUVzdGkuYmMuMjAxOTIzIg0KICApDQoNCmBgYA0KDQoNCiMjIyBDb25zdWx0YSBTUUwNCg0Kc3FsUXVlcnkgcGVybWl0ZSB1dGlsaXphciBlbCBjb2RpZ28gZGUgc3FsIGVuIFIuIExhIGNvbnN1bHRhIHNlIGluc2VydGEgY29tbyBzdHJpbmcuDQoNCkVuIGVzdGEgY29uc3VsdGEgc2VsZWNjaW9uYW1vcyBzZSBjb21iaW5hbiA1IHRhYmxhcyB5IHNlIHNlbGVjY2lvbmEgcGFyYSBlbCBjdWx0aXZvIHRyaWdvLCBlbiBsYSBjYW1wYcOxYSAxOC8xOSwgIGVuIGVsIG5pdmVsIHRlY25vbG9naWNvIGFsdG8sIGVuIGxhIHpvbmEgUmV0YWEgNSBsYXMgZG9zaXMgZGUgZmVydGlsaXphY2lvbiBwcm9tZWRpby4NCg0KYGBge3IsIGVjaG89VH0NCmNvbnN1bHRhX1J1YmVuIDwtIHNxbFF1ZXJ5KGNoYW5uZWwgPSBjaCwgcXVlcnkgPSAiLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2NvbnN1bHRhDQotLTYJRmVydGlsaXphY2nDs24NCi0tNwlIZXJiaWNpZGFzDQotLTgJSW5zZWN0aWNpZGFzDQotLTMJU2llbWJyYQ0KLS0xMCBUcmF0YW1pZW50byBkZSBzZW1pbGxhDQotLTkJRnVuZ2ljaWRhcw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2dyYW5vDQotLTEJVHJpZ28NCi0tMglDZWJhZGENCi0tMwlHaXJhc29sDQotLTQJU29yZ28NCi0tNQlTb2phIDHCsA0KLS02CVNvamEgMsKwDQotLTcJTWHDrXogMcKwIFRlbXByYW5vDQotLTgJTWHDrXogMcKwIFRhcmRpbyB5IDLCsA0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX25pdmVsDQotLTEJQWx0bw0KLS0yCU1lZGlvDQotLTMJQmFqbw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX3pvbmENCi0tMQkgICAgSQlOT0ENCi0tMgkgICAgSUllCU5FQSBFc3RlIChDaGFjbyB5IEZvcm1vc2EpDQotLTMJICAgIElJSQlDdHJvIE4gQ2JhDQotLTQJICAgIElWCVMgQ2JhDQotLTUJICAgIFZjCUN0cm8gTiBTRmUNCi0tNgkgICAgVkkJTsO6Y2xlbyBOb3J0ZQ0KLS03CSAgICBWSUkJTsO6Y2xlbyBTdXINCi0tOAkgICAgVklJSQlDdHJvIEUgRVINCi0tOQkgICAgSVgJTiBMUC1PQkENCi0tMTAJWAlDdHJvIEJBDQotLTExCVhJCVNPIEJBLVMgTFANCi0tMTIJWElJCVNFIEJBDQotLTEzCVhJSUkJU2FuIEx1aXMNCi0tMTQJWElWCUN1ZW5jYSBTYWwNCi0tMTUJWFYJQ29ycmllbnRlcy1NaXNpb25lcw0KLS0xNglJSW8JTkVBIE9lc3RlIChlc3RlIGRlIFNnby4gZGVsIEVzdGVybykNCi0tMTcJVm4JTm9ydGUgU0ZlDQotLS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLw0KLS1AaWRfY2FtcGHDsWENCi0tMQkgMjAxMC8yMDExDQotLTIJIDIwMTEvMjAxMg0KLS0zCSAyMDEyLzIwMTMNCi0tNAkgMjAxMy8yMDE0DQotLTUJIDIwMTQvMjAxNQ0KLS02CSAyMDE1LzIwMTYNCi0tNwkgMjAxNi8yMDE3DQotLTgJIDIwMTcvMjAxOA0KLS05CSAyMDE4LzIwMTkNCi0tMTAgMjAxOS8yMDIwDQoNCmRlY2xhcmUgQGlkX2NhbXBhw7FhIGludA0KZGVjbGFyZSBAaWRfY29uc3VsdGEgaW50DQpkZWNsYXJlIEBpZF9ncmFubyBpbnQNCmRlY2xhcmUgQGlkX25pdmVsIGludA0KZGVjbGFyZSBAaWRfem9uYSBpbnQNCg0Kc2V0IEBpZF9jYW1wYcOxYT0gOSAtLSAyMDE4LzIwMTkNCnNldCBAaWRfY29uc3VsdGE9IDYtLUZlcnRpbGl6YWNpw7NuDQpzZXQgQGlkX2dyYW5vID0gMSAtLVRyaWdvDQpzZXQgQGlkX25pdmVsPSAxIC0tIG5pdmVsIDENCnNldCBAaWRfem9uYSA9IDUgLS0gVmMJQ3RybyBOIFNGZSANCg0KU0VMRUNUIChTRUxFQ1QgZGVzY3JpcGNpb24NCiAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX3Byb21lZGlvcw0KICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSAxKSkgQVMgZGVzX3Byb20sIDEgQVMgdGlwb19wcm9tZWRpbywgeHguaWQsIHh4LmlkX2dyYW5vLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZy5kZXNjcmlwY2lvbiBBUyBkZXNfZ3Jhbm8sIGNjLmlkX3RpcG9fcHJlZ3VudGEsIGNjLmlkX2NhcmFjdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2MuZGVzY3JpcGNpb24gQVMgZGVzX2NhcmFjdCwgbm4uZGVzY3JpcGNpb24gQVMgZGVzX25pdmVsLCB4eC5pZF9uaXZlbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeHguaWRfem9uYSwgenouZGVzY3JpcGNpb24gQVMgRXhwcjEsIHp6LmRlc2NyaXBjaW9uMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwoKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00oU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWF4IElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YSAgRlJPTSB0aXBvX3ByZWd1bnRhX3JldGFhIEFTDQogICAgICAgICAgICAgICAgICAgICAgICAgIHAgTEVGVCBPVVRFUiBKT0lOICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUw0KICAgICAgICAgICAgICAgICAgICAgICAgICBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGEgV0hFUkUgKHAuaWRfZmlsdHJvIElODQogICAgICAgICAgICAgICAgICAgICAgICAgIChjYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzIpLCAwKSBBUyBERUNJTUFMKDEwLCAyKSkgQVMgQWx0b19Qcm9tZWRpb19tYXgsICdodHRwOi8vYmMtc2VsbG9zL1BydWViYVJldGFhL3BvcF91cF9YX3J1YnJvcy5hc3B4P3Bhcj0nICsgQ0FTVChAaWRfY2FtcGHDsWEgQVMgbnZhcmNoYXIoMSkpIA0KICAgICAgICAgICAgICAgICAgKyAnOycgKyBDQVNUKHh4LmlkX2dyYW5vIEFTIG52YXJjaGFyKDIpKSArICc7JyArIENBU1QoeHguaWRfem9uYSBBUyBudmFyY2hhcigyKSkgKyAnOycgKyBDQVNUKGNjLmlkX3RpcG9fcHJlZ3VudGEgQVMgbnZhcmNoYXIoMikpICsgJzsnICsgQ0FTVChjYy5pZF9jYXJhY3RfMiBBUyBudmFyY2hhcigzKSkgKyAnOycgKyBDQVNUKHh4LmlkX25pdmVsIEFTIG52YXJjaGFyKDMpKSArICc7JyArICcwJyBBUyBVUkwsIA0KICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBTVU0obWluKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCBJU05VTEwodC5taW4sIDApIEFTIG1pbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWluIElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhIEFTIGMgT04gcC5pZCA9IGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAocC5pZF9maWx0cm8gPSBjYy5pZF90aXBvX3ByZWd1bnRhKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGMuaWRfdGlwb19wcmVndW50YSkpIEFORCAodC5uaXZlbCA9IHh4LmlkX25pdmVsKSBBTkQgKHQubWluX2VzdGFkbyA9IDEpIEFORCAodC5pZF9jYXJhY3QgPSBjYy5pZF9jYXJhY3RfMikgQU5EICh0LmVzdGFkb19uaXZlbCA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV83DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMSksIDApIEFTIERFQ0lNQUwoMTAsIDIpKSBBUyBBbHRvX1Byb21lZGlvX21pbiwgSVNOVUxMDQogICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgU1VNKG1heF9udWxsKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCAoQ0FTRSBXSEVOIHBvcmNfYXBsaWMgSVMgTlVMTCBUSEVOIElTTlVMTCh0IC5tYXgsIDApIEVMU0UgSVNOVUxMKHQgLm1heCwgMCkgKiBwb3JjX2FwbGljIC8gMTAwIEVORCkgQVMgbWF4X251bGwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhIEFTIHAgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvID0gY2MuaWRfdGlwb19wcmVndW50YSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgZ2dfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWF4X251bGwsIElTTlVMTA0KICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIFNVTShtYXhfbnVsbCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgKENBU0UgV0hFTiBwb3JjX2FwbGljIElTIE5VTEwgVEhFTiBJU05VTEwodCAubWluLCAwKSBFTFNFIElTTlVMTCh0IC5taW4sIDApICogcG9yY19hcGxpYyAvIDEwMCBFTkQpIEFTIG1heF9udWxsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhX3RyYW5zIEFTIHQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgdGlwb19wcmVndW50YV9yZXRhYSBBUyBwIExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChwLmlkX2ZpbHRybyA9IGNjLmlkX3RpcG9fcHJlZ3VudGEpIEFORCAoYy5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5taW5fZXN0YWRvID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGNjLmlkX2NhcmFjdF8yKSBBTkQgKHQuZXN0YWRvX25pdmVsID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGdnXzFfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWluX251bGwsIGNjLmlkX2luZGljZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGRlc2NyaXBjaW9uDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZmlsdHJvDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgdGlwb19wcmVndW50YV9yZXRhYV8zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgSU4gKGNjLmlkX3RpcG9fcHJlZ3VudGEpKSkpKSBBUyBkZXNfY29uc3VsdGEsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKChTRUxFQ1QgU1VNKG1heCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhcmFjdF9pZF9ncmFubyBBUyBjYXJhY3RfaWRfZ3Jhbm9fMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzIpICsNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFNVTShtaW4pIC8gQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgSVNOVUxMKHQubWluLCAwKSBBUyBtaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYXJhY3RfaWRfZ3Jhbm8gQVMgY2FyYWN0X2lkX2dyYW5vXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkpKSBBTkQgKHQubml2ZWwgPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkgQU5EICh0Lm1pbl9lc3RhZG8gPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgYV8yXzFfMV8xKSkgLyAyIC8gMTAwICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llXzIsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBzdXBlcmZpY2llDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llLCB6ei5pbmRpY2UsDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0gMikgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5pZF9jYXJhY3QgPSA0KSBBTkQgKHQubWF4X2VzdGFkbyA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMV8xKSBBUyBBbHRvX1Byb21lZGlvX21heF9kaXN0cmlidWNpb24sDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgSURfTUFQQQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19ncmFub19yZXBvcnRlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZCA9IGdnLmlkX2dyYW5vX3JlcG9ydCkpKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FyYWN0X2lkX2dyYW5vIEFTIGNhcmFjdF9pZF9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV8yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzJfMSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18xDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgc3VwZXJmaWNpZV8zLA0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgcHJpbWVyYQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZ3Jhbm9fcmVwb3J0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fZ3Jhbm8gQVMgVGlwb19ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSB4eC5pZF9ncmFubykpKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18zDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgUGFzX3ByaW1lcmFfc3VwZXJmaWNpZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHNlZ3VuZGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGlkX2dyYW5vX3JlcG9ydA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2dyYW5vIEFTIFRpcG9fZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0geHguaWRfZ3Jhbm8pKSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkpICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fNA0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIC8gMTAwIEFTIHBhc19zZWd1bmRhX3N1cGVyZmljaWUsIGNjLnRpcG9fdW5pZGFkLCBDQVNFIFdIRU4gY2MuaWRfdGlwb19wcmVndW50YSA9IDcgT1INCiAgICAgICAgICAgICAgICAgIGNjLmlkX3RpcG9fcHJlZ3VudGEgPSA2IFRIRU4NCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgQ29lZmljaWVudGUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0KSBFTFNFICctMScgRU5EIEFTIGNvZWZpY2llbnRlLCBsLmRlc2NyaXBjaW9uIEFTIGNhbXBhw7FhDQpGUk9NICAgICBHcmFub3Nfem9uYXNfcmV0YWEgQVMgeHggTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX3pvbmFfcmV0YWEgQVMgenogT04geHguaWRfem9uYSA9IHp6LmlkX3pvbmEgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX25pdmVsIEFTIG5uIE9OIHh4LmlkX25pdmVsID0gbm4uaWRfbml2ZWwgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2dyYW5vIEFTIGdnIE9OIHh4LmlkX2dyYW5vID0gZ2cuaWQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjYyBPTiB4eC5pZF9ncmFubyA9IGNjLmlkX2dyYW5vIEFORCBjYy5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvIElOIChAaWRfY29uc3VsdGEpKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgIEHDsW9fY2FtcGHDsWFzIEFTIGwgT04gY2MuaWRfY2FtcGHDsWEgPSBsLmlkDQpXSEVSRSAgKHh4LmlkX2dyYW5vIElOIChAaWRfZ3Jhbm8pKSBBTkQgKHh4LmlkX3pvbmEgSU4gKEBpZF96b25hKSkgQU5EICh4eC5pZF9uaXZlbCBJTiAoQGlkX25pdmVsKSkgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDQpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA1KSBBTkQgKGNjLmlkX2NhcmFjdF8yIDw+IDEwNikgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDcpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA4KSBBTkQgDQogICAgICAgICAgICAgICAgICAoY2MuaWRfY2FyYWN0XzIgPD4gNjUpIEFORCAoY2MuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpOyIpDQoNCg0KY29uc3VsdGFfUnViZW4NCmBgYA0KDQojIyMgUGFxdWV0ZSBgREJJYA0KDQpEQkkgcGVybWl0ZSBjb25lY3Rhcm5vIGEgbGEgYmFzZSBkZSBkYXRvcyBkZSBTUUwuIFBhcmEgaGFjZXJsbyBkZWJlbW9zIGNvbmZpZ3VyYXIgbG9zIGNhbXBvcy4gTGEgY29uZXhpw7NuIHNlIHB1ZWRlIHZlcmlmaWNhciBlbiBlbCBwYW5lbCBzdXBlcmlvciBkZXJlY2hvLg0KDQpMYSBiYXNlIGRhdG9zIGRlbCBSZVRBQSBlc3RhIGNvbXB1ZXN0YSBwb3IgNiB0YWJsYXMgcHJpbmNpcGFsZXMgIkHDsW8gQ2FtcGHDsWFzIiwgImNhYmVjZXJhX3RybnNhY2Npb25lc19yZXRhYSIsICAiY2FyYWN0X2lkX2dyYW5vIiwgImNhcmFjdF9pZF9ncmFub19jYW1wYcODwrFhX3Zpc3RhIiwgIkNvbGFib3JhZG9yZXMiICB5ICJHcmFub3Nfem9uYXNfcmV0YWEiLg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI01lIGNvbmVjdG8gYSBsYSBiYXNlDQpjb24gPC0gREJJOjpkYkNvbm5lY3Qob2RiYzo6b2RiYygpLA0KICAgICAgICAgICAgICAgICAgICAgIERyaXZlciAgICA9ICJTUUwgU2VydmVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgU2VydmVyICAgID0gIkJDLVJFVEEiLA0KICAgICAgICAgICAgICAgICAgICAgIERhdGFiYXNlICA9ICJFc3RpbWFjaW9uZXNfY29waWEiLA0KICAgICAgICAgICAgICAgICAgICAgIFVJRCAgICAgICA9ICJlc3RpbWFjaW9uZXNfY29uc3VsdGEiLA0KICAgICAgICAgICAgICAgICAgICAgIFBXRCAgICAgICA9ICJFc3RpLmJjLjIwMTkyMyIsDQogICAgICAgICAgICAgICAgICAgICAgUG9ydCAgICAgID0gMTQzMywNCiAgICAgICAgICAgICAgICAgICAgICBkYm5hbWUgPSAiRXN0aW1hY2lvbmVzX0NvcGlhIiwNCiAgICAgICAgICAgICAgICAgICAgICBlbmNvZGluZyA9ICJsYXRpbjEiKQ0KDQpEQkk6OmRiTGlzdFRhYmxlcyhjb24pWzE6Nl0jbGlzdGEgZGUgbGFzIHRhYmxhcyBkZSBsYSBiYXNlDQpgYGANCiANCmxhIGZ1bmNpw7NuIGB0YmxgIGRlIGBkcGx5cmAgdHJhZSBsYXMgdGFibGFzIGRlIGxhIGJhc2UgZGUgZGF0b3MuIFRhbWJpZW4gcG9kZW1vcyBhcGxpY2FyIGEgZXN0YSB0YWJsYSB0b2RhcyBsYXMgZnVuY2lvbmVzIHF1ZSB2aW1vcyBlbiBsYXMgY2xhc2VzIHByZXZpYXMuDQoNClZlYW1vcyBhbGd1bmFzIGRlIGxhcyB0YWJsYXMgcXVlIGNvbmZvcm1hbiBsYSBiYXNlIGRlbCBSZVRBQS4NCg0KDQojIyMjIFRhYmxhIFRpcG9fZ3Jhbm8NCmBgYHtyLCBlY2hvPVRSVUV9DQojVGFibGEgaWQgZ3Jhbm8NClRpcG9fZ3Jhbm8gPC0gIHRibChjb24sIGMoIlRpcG9fZ3Jhbm8iKSkgJT4lIA0KICBzZWxlY3QoaWQsZGVzY3JpcGNpb24pICU+JSByZW5hbWUoaWRfZ3Jhbm8gPSBpZCwgZGVzY3JpcGNpb25fZ3Jhbm8gPSBkZXNjcmlwY2lvbikgJT4lIGZpbHRlcihpZF9ncmFubz4wKQ0KVGlwb19ncmFubyANCmBgYA0KDQojIyMjIFRhYmxhIEHDsW9fY2FtcGHDsWFzDQpgYGB7ciwgZWNobz1UUlVFfQ0KI3NlbGVjY2lvbm8gdGFibGEgaWQgY2FtcGHDsWENCkFuaW9fY2FtcGFuaWFzIDwtICB0YmwoY29uLCBjKCJBw7FvX2NhbXBhw7FhcyIpKSAlPiUgcmVuYW1lKGlkX2NhbXBhbmlhID0gaWQsIGRlc2NyaXBjaW9uX2NhbXBhbmlhID0gZGVzY3JpcGNpb24pICU+JSBmaWx0ZXIoaWRfY2FtcGFuaWE+MCkNCg0KQW5pb19jYW1wYW5pYXMgDQpgYGANCg0KIyMjIyBUYWJsYSBUaXBvX3pvbmFfcmV0YWENCmBgYHtyLCBlY2hvPVRSVUV9DQojY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KVGlwb196b25hX3JldGFhIDwtIHRibChjb24sIGMoIlRpcG9fem9uYV9yZXRhYSIpKSAlPiUgc2VsZWN0KGlkX3pvbmEsZGVzY3JpcGNpb24sZGVzY3JpcGNpb24yKSAlPiUgcmVuYW1lKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEgPSBkZXNjcmlwY2lvbiwNCiAgICAgICBkZXNjcmlwY2lvbl96b25hX3JldGFhMiA9IGRlc2NyaXBjaW9uMikNClRpcG9fem9uYV9yZXRhYSAgJT4lIGhlYWQoMTApDQpgYGANCg0KIyMjIyBUYWJsYSBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQpgYGB7ciwgZWNobz1UUlVFfQ0KI2NhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWENCmNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgPC0gdGJsKGNvbiwgYygiY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSIpKSAlPiUgc2VsZWN0KGlkX3RyYW5zLGlkX2NvbGFib3JhZG9yLGVzdGFkbykNCmNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgICU+JSBoZWFkKDEwKQ0KYGBgDQoNCiMjIyMgVGFibGEgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWENCmBgYHtyICwgZWNobz1UUlVFfQ0KI1RhYmxhIGNhcmFjdGVyaXN0aWNhcyByZXRhYSAoUHJpbmNpcGFsKQ0KVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgPC0gdGJsKGNvbiwgYygiVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMiKSkNClRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhICAlPiUgaGVhZCgxMCkNCmBgYA0KDQojIyMjIFRhYmxhIENvbGFib3JhZG9yZXMNCg0KYGBge3IsIGVjaG89VFJVRX0NCiNUYWJsYSBDb2xhYm9yYWRvcmVzDQpDb2xhYm9yYWRvcmVzIDwtIHRibChjb24sIGMoIkNvbGFib3JhZG9yZXMiKSkNCkNvbGFib3JhZG9yZXMgJT4lIHZhcmlhYmxlLm5hbWVzKCkNCmBgYA0KDQpUYW1iaWVuIHBvZGVtb3MgdmlzdWFsaXphciBsYXMgY29uZXh4aW9uZXMgZW50cmUgbGFzIHRhYmxhcyBjb24gZWwgcGFxdWV0ZSBgZGF0YW1vZGVscmAgcXVlIG5vcyBwZXJtaXRlIGNvbnN0cnVpciBkaWFncmFtYXMgZW50aWRhZC1yZWFsYWNpw7NuDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05fQ0KbGlicmFyeShkYXRhbW9kZWxyKSAjcGFxdWV0ZSBwYXJhIGFybWFyIGRpYWdyYW1hIGRlIGVudGlkYWQgcmVsYWNpb24NCg0KY29uZWNjaW9uIDwtIG9kYmNEcml2ZXJDb25uZWN0KA0KICBjb25uZWN0aW9uID0gIkRyaXZlcj1TUUwgU2VydmVyOyBTZXJ2ZXI9QkMtUkVUQTsgRGF0YWJhc2U9RXN0aW1hY2lvbmVzX2NvcGlhOyBVSUQ9ZXN0aW1hY2lvbmVzX2NvbnN1bHRhOyBQd2Q9RXN0aS5iYy4yMDE5MjMiDQogICkNCg0Kc1F1ZXJ5IDwtIGRtX3JlX3F1ZXJ5KCJzcWxzZXJ2ZXIiKQ0KZG1fcmV0YWEgPC0gc3FsUXVlcnkoY2hhbm5lbCA9IGNvbmVjY2lvbiwgc1F1ZXJ5LCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGVycm9ycz1UUlVFKQ0KZG1fcmV0YWEgPC0gYXMuZGF0YV9tb2RlbChkbV9yZXRhYSkgI3Bhc28gYSBmb3JtYXRvIG1vZGVsbw0KDQpmb2N1cyA8LWxpc3QodGFibGVzICA9IGMoIkHDsW9fY2FtcGHDsWFzIiwiY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSIsImNhcmFjdF9pZF9ncmFubyIsICAgICAgICAgICAgICAgDQoiY2FyYWN0X2lkX2dyYW5vX2NhbXBhw7FhX3Zpc3RhIiwiQ29sYWJvcmFkb3JlcyIsIkdyYW5vc196b25hc19yZXRhYSIpKSANCiANCmdyYXBoIDwtIGRtX2NyZWF0ZV9ncmFwaChkbV9yZXRhYSAsIHJhbmtkaXIgPSAiQlQiLCBmb2N1cyA9IGZvY3VzLCBjb2xfYXR0ciA9IGMoImNvbHVtbiIsICJ0eXBlIikpIA0KZG1fcmVuZGVyX2dyYXBoKGdyYXBoKSAjZ3JhZmljbw0KYGBgDQoNCg0KIyMjIFF1ZXJ5IFNRTCB2cyBkcGx5cg0KDQpFbiBlc3RhIHNlY2Npb24gdmFtb3MgYSByZXBsaWNhciBsYSBjb25zdWx0YSBTUUwgcXVlIHZpbW9zIGFycmliYSBwZXJvIGVuIGZvbXJhdG8gZHBseXIuIFZhbW9zIGEgdmVyIHF1ZSB1bmEgY29uc3VsdGEgbXV5IGV4dGVuc2Egc2UgcHVlZGUgcmVhbGl6YXIgZW4gdW5hIGZvbXJhIG3DoXMgcHJvbGlqYSB5IGJyZXZlLg0KDQpFbCBjb21hbmRvYHNob3dfcXVlcnlgIHBlcm1pdGUgZXh0cmFlciBsYSBjb25zdWx0YSBlbiBmb3JtYXRvIFNRTC4NCg0KYGBge3IsIGVjaG89VFJVRX0NCg0KdGFibGFfY29uc3VsdGFfc3FsIDwtIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhICU+JSAgDQogIGxlZnRfam9pbihjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhLGJ5ID0gYygiaWRfdHJhbnMiLCJpZF9jb2xhYm9yYWRvciIpKSAlPiUgI2pvaW4gY29uIHRhYmxhIGNhYmVjZXJhDQogIGxlZnRfam9pbihUaXBvX2dyYW5vICxieSA9ICJpZF9ncmFubyIpICU+JQ0KICBsZWZ0X2pvaW4oQW5pb19jYW1wYW5pYXMgLGJ5ID0gYygiaWRfY2FtcGHDsWEiPSJpZF9jYW1wYW5pYSIpICkgJT4lDQogIGxlZnRfam9pbihUaXBvX3pvbmFfcmV0YWEsIGJ5ID0gYygiaWRfem9uYSIpICApICU+JSANCiAgZmlsdGVyKGlkX2NhbXBhw7FhID09IDksaWRfem9uYT09NSxuaXZlbD09MSxpZF9ncmFubz09MSxpZF90aXBvX3ByZWd1bnRhPT02LCBtYXhfZXN0YWRvID09IDEsIGVzdGFkbz09MSkgJT4lDQogIGdyb3VwX2J5KGRlc2NyaXBjaW9uX2dyYW5vLCBpZF9ncmFubywgZGVzY3JpcGNpb25fY2FtcGFuaWEsIGlkX2NhbXBhw7FhLCBkZXNjcmlwY2lvbl96b25hX3JldGFhLCBpZF96b25hLA0KICAgICAgICAgIG5pdmVsLCBpZF90aXBvX3ByZWd1bnRhLCBpZF9jYXJhY3QsZGVzY3JpcGNpb24pICU+JSANCiAgc3VtbWFyaXNlKHByb21lZGlvX21heCA9IHJvdW5kKG1lYW4obWF4LCBuYS5ybSA9IFQpLDIpLA0KICAgICAgICAgICAgcHJvbWVkaW9fbWluID0gcm91bmQobWVhbihtaW4sIG5hLnJtID0gVCksMikpIA0KDQp0YWJsYV9jb25zdWx0YV9zcWwgJT4lIGRwbHlyOjpzaG93X3F1ZXJ5KCkgI3ZlciBxdWVyeSBTUUwNCg0KdGFibGFfY29uc3VsdGFfc3FsICNzYWxpZGENCg0KYGBgDQoNCiMjIyBQbGFudGVvcyBUZWNub2xvZ2ljb3MNCg0KQ29uc3RydWlyIGxvcyBwbGFudGVvcyB0ZWNub2zDs2dpY29zIHN1ZWxlIHNlciB1biB0cmFiYWpvIHF1ZSB0ZWRpb3NvIHF1ZSBubyBlc3RhIGF1dG9tYXRpemFkbyB5IHN1ZWxlIHRvbWFyIGJhc3RhbnRlIHRpZW1wby4gRW4gZXN0YSBzZWNjacOzbiBidXNjYW1vcyBhdXRvbWF0aXphciBsYSBjb25zdHJ1Y2Npw7NuIGRlIGxvcyBwbGFudGVvcy4NCg0KYGBge3IsIGVjaG89VFJVRX0NCiMgdGFibGEgY29uIHRvZGFzIGxvcyBpbnN1bW9zIGluY2x1aWRvcyBlbiBsYSBiYXNlDQp0YWJsYV92YXJpYWJsZXMgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lIGRpc3RpbmN0KGRlc2NyaXBjaW9uLHRpcG9fdW5pZGFkKSAlPiUgYXNfdGliYmxlKCkNCg0KI2xpc3RhIGRlIHZhcmlhYmxlcyBpbmNsdWlkYXMNCnZhcmlhYmxlc19wbGFudGVvIDwtIGMoIkFkb3BjacOzbiBkZSBOVCIsIm1heF9taW4iLCJuaXZlbCIsImlkX2NhbXBhw7FhIiwiaWRfZ3Jhbm8iLCJpZF96b25hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImRlc2NyX2dyYW5vIiwiZGVzY3JfY2FtcGFuaWEiLCJTZW1pbGxhIiwiVXJlYSIsIlBEQSIsIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIEJhcmJlY2hvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIGN1bHRpdm8iLCJIaWIuIFJSIEJ0MiIsIjItNEQiLCJEaWNhbWJhIiwiTWV0c3VsZnVyw7NuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIlNQUyIsIkF0cmF6aW5hIiwiTWV0b2xhY2xvciIsIlBpY2xvcsOhbSIsIkRpYW1pZGFzIiwiRGljbG9zdWxhbSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAiRnVuZ2ljaWRhIDEgKEVzdHJvYi4gKyBUcmlhem9sKSIsIlNlbWlsbGEiLCAiSW5vYy4gKyBGdW5naWMuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIklub2N1bGFudGUgMSAoZnVsbCkiLCJGb3Nmb3JhZG9zIDEiLCAiRm9zZm9yYWRvcyAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIkN1cmFzZW1pbGxhIC0gRnVuZ2ljaWRhIGJhc2UiLCJDbG9yaW11csOzbiIpDQoNCg0KI0FybW8gbGEgY29uc3VsdGEgZGUgcGxhbnRlb3MNCnBsYW50ZW9zIDwtIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhICU+JSAgDQogIGZpbHRlcihkZXNjcmlwY2lvbiAlaW4lIHZhcmlhYmxlc19wbGFudGVvKSAlPiUgI21lIHF1ZWRvIGNvbiBpbnN1bW9zIGluY2x1aWRvcyBlbiBsb3MgcGxhbnRlb3MNCiAgbGVmdF9qb2luKGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEsIGJ5ID0gYygiaWRfdHJhbnMiLCJpZF9jb2xhYm9yYWRvciIpKSAlPiUgDQogIGxlZnRfam9pbihUaXBvX3pvbmFfcmV0YWEsIGJ5PWMoImlkX3pvbmEiKSkgJT4lIA0KICBsZWZ0X2pvaW4oVGlwb19ncmFubywgYnk9ImlkX2dyYW5vIikgJT4lIA0KICBsZWZ0X2pvaW4oQW5pb19jYW1wYW5pYXMsYnk9YygiaWRfY2FtcGHDsWEiPSJpZF9jYW1wYW5pYSIgKSkgJT4lICANCiAgZmlsdGVyKGVzdGFkbz09MSkgJT4lICNlbmN1ZXN0YXMgdmFsaWRhZGFzIA0KICBhc190aWJibGUoKSAlPiUgDQogICNDYWxjdWxvIHByb21lZGlvIHBvciBjYW1wYcOxYSwgbml2ZWwsIHpvbmEsIGluc3VtbyB5IGdyYW5vDQogIGdyb3VwX2J5KCBpZF9jYW1wYcOxYSAsZGVzY3JpcGNpb25fY2FtcGFuaWEgLCBuaXZlbCwgaWRfem9uYSwgZGVzY3JpcGNpb25fem9uYV9yZXRhYSwNCiAgICAgICAgICAgIGlkX2dyYW5vLCBkZXNjcmlwY2lvbl9ncmFubywgZGVzY3JpcGNpb24gKSAlPiUgIA0KICBzdW1tYXJpc2UocHJvbWVkaW9fbWF4ID0gbWVhbihtYXgsIG5hLnJtID0gVCksICNwcm9lbWRpbyBtYXhpbW8gYXBsaWNhZG8NCiAgICAgICAgICAgIHByb21lZGlvX21pbiA9IG1lYW4obWluLCBuYS5ybSA9IFQpLCAjcHJvbWVkaW8gbWluaW1vIGFwbGljYWRvDQogICAgICAgICAgICBwcm9tZWRpb19wb3JjX2FwbGljID0gbWVhbihwb3JjX2FwbGljLCBuYS5ybSA9IFQpDQogICAgICAgICAgICApICU+JSAjY2FudGlkYWQgZGUgZW5jdWVzdGFzIHJlYWxpemFkYXMNCiAgbXV0YXRlKHByb21lZGlvID0gKHByb21lZGlvX21pbitwcm9tZWRpb19tYXgpLzIsICNjYWxjdWxvIHByb21lZGlvDQogICAgICAgICBwcm9tZWRpbyA9IGlmZWxzZShpcy5uYShwcm9tZWRpbyksMCxwcm9tZWRpbykNCiAgICAgICAgICkgJT4lIA0KICAgc2VsZWN0KC1jKHByb21lZGlvX21heCxwcm9tZWRpb19taW4scHJvbWVkaW9fcG9yY19hcGxpYykgKSAgDQogIA0KDQojRnVuY2lvbiBwYXJhIGVzY2FsYXIgZWwgbml2ZWwgZGUgYWRvcGNpb24gdGVjbm9sb2dpY2ENCmVzY2FsYXIgPC0gZnVuY3Rpb24oeCl7IHggPSB4L3N1bSh4LG5hLnJtID0gVCkgKjEwMCB9DQoNCiNHZW5lcm8gZGVzY3JpcGNpb24gTml2ZWwgVGVjbm9sw7NnaWNvDQpwbGFudGVvcyA8LSBwbGFudGVvcyAlPiUNCiAgbXV0YXRlKGRlc2NyaXBjaW9uX25pdmVsID0gY2FzZV93aGVuKG5pdmVsID09IDEgfiAiQWx0byIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuaXZlbCA9PSAyIH4gIk1lZGlvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5pdmVsID09IDMgfiAiQmFqbyIpKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBkZXNjcmlwY2lvbix2YWx1ZXNfZnJvbSA9IHByb21lZGlvKSAlPiUgDQogIGdyb3VwX2J5KGlkX2NhbXBhw7FhLGlkX3pvbmEsaWRfZ3Jhbm8pICU+JQ0KICBtdXRhdGUoQWRvcGNpb25fTlQgPSBlc2NhbGFyKGBBZG9wY2nDs24gZGUgTlRgKSkNCg0KcGxhbnRlb3MgJT4lIGhlYWQoKQ0KDQpgYGANCg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KcGxhbnRlb3NfbG9uZyA8LSBwbGFudGVvcyAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYygxOjgsQWRvcGNpb25fTlQpLCBuYW1lc190byA9ICJ2YXJpYWJsZXMiLCB2YWx1ZXNfdG8gPSAidmFsb3JlcyIpICU+JSBtdXRhdGUodmFsb3JlcyA9IGlmZWxzZShpcy5uYSh2YWxvcmVzKSwwLHZhbG9yZXMpKSAlPiUgZ3JvdXBfYnkoaWRfY2FtcGHDsWEsZGVzY3JpcGNpb25fY2FtcGFuaWEsaWRfem9uYSwNCmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEsIGlkX2dyYW5vLGRlc2NyaXBjaW9uX2dyYW5vLCB2YXJpYWJsZXMpICU+JSBzdW1tYXJpc2UodmFsb3JlcyA9ICB3ZWlnaHRlZC5tZWFuKHZhbG9yZXMgLHcgPSBBZG9wY2lvbl9OVC8xMDApKQ0KDQpwbGFudGVvc19sb25nICAlPiUgIGhlYWQoKQ0KYGBgDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05LCBlY2hvPVRSVUV9DQp2YXJpYWJsZXNfcGxhbnRlb19zb2phIDwtYygiU2VtaWxsYSIsICJTUFMiLCJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBCYXJiZWNobyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiR2xpZm9zYXRvIGNvbmNlbnRyYWRvIC0gY3VsdGl2byIsICIyLTREIiwiQ2xvcmltdXLDs24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1ldHN1bGZ1csOzbiIsIkRpY2xvc3VsYW0iLCJEaWFtaWRhcyIsIkVzdHJvYmlydWxpbmEgKyBUcmlhem9sIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbm9jdWxhbnRlIDEgKGZ1bGwpIiwiSW5vYy4gKyBGdW5naWMuIikgI0xhbWJkYWNpYWxvdHJpbmEgbm8gbG8gZW5jb250csOpDQoNCnBsYW50ZW9zX2xvbmcgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iU29qYSAxwrAiLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX3NvamEpICU+JSANCiAgZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh5PXZhbG9yZXMseD1kZXNjcmlwY2lvbl9jYW1wYW5pYSwgY29sb3I9YXMuZmFjdG9yKGlkX3pvbmEpKSkrIA0KICBnZW9tX3BvaW50KCkgKyBmYWNldF93cmFwKH52YXJpYWJsZXMsIHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgbGFicyh0aXRsZSA9ICAiRG9zaXMgYXBsaWNhZGFzIC0gU29qYSAxwroiKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGZpbGw9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICAgICAgICkgDQpgYGANCg0KDQojIyMgQW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBkYXRvcyANCg0KDQojIyMjIEV2b2x1Y2nDs24gZGVsIG5pdmVsIHRlY25vbMOzZ2ljbw0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJNYcOteiAxwrAgVGVtcHJhbm8iKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IEFkb3BjaW9uX05ULCBncm91cD1uaXZlbCxmaWxsID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKyAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZSA9ICAiTml2ZWwgdGVjbm9sw7NnaWNvIHBvciB6b25hIC0gTWHDrXogdGVtcHJhbm8iKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGZpbGw9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKSANCmBgYA0KDQoNCiMjIyMgRG9zaXMgZGUgZmVydGlsaXphY2nDs24gVXJlYQ0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCiNHcmFmaWNvDQpwbGFudGVvcyAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iTWHDrXogMcKwIFRlbXByYW5vIikgICU+JSAgI2ZpbHRybyBjdWx0aXZvDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwNCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IFVyZWEsIGdyb3VwPW5pdmVsLGNvbG9yID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkrDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpICsgIA0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICAiRmVydGlsaXphY2nDs24gY29uIFVyZWEgKGtnL2hhKSBlbiBNYcOteiB0ZW1wcmFubyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgY29sb3I9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKQ0KYGBgDQoNCg0KDQoNCg0K